<template>
  <el-form
    ref="ruleForm"
    :key="freshKey"
    class="common-form"
    :label-width="labelWidth"
    :size="size"
    :model="form"
    :rules="rules"
    @submit.stop="subForm"
  >
    <el-row class="common-form-wrap">
      <el-col
        v-for="(v, i) in formInfoTmp"
        v-show="
          !hideMore ||
            (v.type != 'hidden' &&
              (v.isHide ? v.isHide() : true) &&
              ((hideMore && toggle) || i < splice))
        "
        :key="i"
        :md="v.isFull ? 24 : 12"
        :lg="v.isFull ? 24 : v.span ? v.span : 24 / splice"
      >
        <el-form-item
          :prop="v.type == 'rangNum' ? v.childName[0] : v.name"
          :required="v.required"
          :rules="v.type != 'hidden' && v.rules ? v.rules : null"
          :label="v.title"
          :label-width="!v.title ? '0px' : v.labelWidth || labelWidth"
        >
          <!-- textarea输入框 -->
          <el-input
            v-if="v.type == 'textarea'"
            :id="v.name"
            v-model="form[v.name]"
            type="textarea"
            :disabled="disabled || v.readonly"
            :clearable="!v.noClear"
            :placeholder-text="v.placeholder || `请输入${v.title}${v.required ? '（必填）' : ''}`"
            :maxlength="v.maxLen || 500"
            :autosize="v.autoSize || { minRows: 4, maxRows: 6 }"
            show-word-limit
          />
          <!-- 数字输入框 -->
          <el-input-number
            v-else-if="v.type == 'number'"
            v-model="form[v.name]"
            :precision="v.precision"
            :disabled="disabled || v.readonly"
            :min="v.min"
            :max="v.max"
            :controls="false"
            :placeholder="
              disabled || v.readonly
                ? ''
                : v.placeholder || `请输入${v.title}${v.required ? '（必填）' : ''}`
            "
          />
          <!-- 单选 -->
          <el-radio-group
            v-else-if="v.type == 'radio'"
            v-model="form[v.name]"
            :disabled="disabled || v.readonly"
          >
            <el-radio v-for="(r, k) in v.child" :key="k" :value="r.value">
              {{ r.label }}
            </el-radio>
          </el-radio-group>
          <!-- 开关 -->
          <el-switch
            v-else-if="v.type == 'switch'"
            v-model="form[v.name]"
            :disabled="disabled || v.readonly"
          />
          <!-- 多选 -->
          <el-checkbox-group
            v-if="v.type == 'checkbox'"
            v-model="form[v.name]"
            :disabled="disabled || v.readonly"
            :options="v.child"
          />
          <!-- 单时间 -->
          <el-date-picker
            v-else-if="v.type == 'date'"
            v-model="form[v.name]"
            :value-format="v.format || 'YYYY-MM-DD'"
            format="YYYY-MM-DD"
            :disabled="disabled || v.readonly"
            :placeholder="v.placeholder || `请选择${v.title}${v.required ? '（必填）' : ''}`"
          />
          <el-date-picker
            v-else-if="v.type == 'datetime'"
            v-model="form[v.name]"
            :value-format="v.format || 'YYYY-MM-DD HH:mm:ss'"
            type="datetime"
            :disabled="disabled || v.readonly"
            :placeholder="v.placeholder || `请选择${v.title}${v.required ? '（必填）' : ''}`"
          />
          <!-- 日期范围 -->
          <template
            v-else-if="v.type == 'daterange' || v.type == 'monthrange' || v.type == 'yearrange'"
          >
            <el-date-picker
              v-model="form[v.name]"
              :disabled="disabled || v.readonly"
              :value-format="v.format || 'YYYY-MM-DD'"
              format="YYYY-MM-DD"
              :type="v.type"
              :start-placeholder="v.placeholder ? v.placeholder[0] : '开始日期'"
              :end-placeholder="v.placeholder ? v.placeholder[1] : '结束日期'"
            />
          </template>
          <!-- 日期范围 -->
          <el-date-picker
            v-else-if="v.type == 'datetimerange'"
            v-model="form[v.name]"
            :value-format="v.format || 'YYYY-MM-DD HH:mm:ss'"
            :disabled="disabled || v.readonly"
            type="datetimerange"
            :start-placeholder="v.placeholder ? v.placeholder[0] : '开始时间'"
            :end-placeholder="v.placeholder ? v.placeholder[1] : '结束时间'"
          />
          <!-- 下拉选择 -->
          <el-select
            v-else-if="v.type == 'select'"
            v-model="form[v.name]"
            :multiple="v.multi"
            :disabled="disabled || v.readonly"
            :clearable="!v.noClear"
            collapse-tags
            collapse-tags-tip
            :placeholder="v.placeholder || `请选择${v.title}${v.required ? '（必填）' : ''}`"
            @change="val => changeSelect(val, v)"
          >
            <el-option v-for="r in v.child" :key="r.value" :value="r.value" :label="r.label" />
          </el-select>
          <!-- 数字区间 -->
          <template v-else-if="v.type == 'rangNum'">
            <el-row class="">
              <el-col :span="11">
                <el-input-number
                  v-model="form[v.childName[0]]"
                  :disabled="disabled || v.readonly"
                  :min="v.min"
                  :controls="v.controls"
                  controls-position="right"
                  :placeholder="v.placeholder?.split(',').shift()"
                  :max="form[v.childName[1]] ? form[v.childName[1]] : 10000"
                />
              </el-col>
              <el-col :span="2" style="text-align: center">-</el-col>
              <el-col :span="11">
                <el-form-item label-width="0" :prop="v.childName[1]">
                  <el-input-number
                    v-model="form[v.childName[1]]"
                    :disabled="disabled || v.readonly"
                    :min="form[v.childName[0]] ? form[v.childName[0]] : v.min"
                    :max="v.max"
                    :placeholder="v.placeholder?.split(',').pop()"
                    :controls="v.controls"
                    controls-position="right"
                  />
                </el-form-item>
              </el-col>
            </el-row>
          </template>
          <!-- 对象 -->
          <el-input
            v-else-if="v.type == 'obj'"
            :value="form[v.name][v.objName]"
            read-only
            :disabled="disabled || v.readonly"
          />
          <!-- 图片上传 -->
          <image-upload v-if="v.type == 'image-upload'" v-model="form[v.name]" v-bind="v" />
          <!--文件上传 -->
          <template v-if="v.type == 'file-upload'">
            <file-upload v-model="form[v.name]" v-bind="v" :disabled="disabled || v.readonly" />
          </template>

          <!-- 纯展示文字描述 -->
          <div v-else-if="v.type == 'info'" class="info-value">
            {{ v.value || form[v.name] }}
          </div>
          <!-- 自带请求地址的选择下拉 -->
          <cu-select
            v-else-if="v.type == 'cuselect'"
            v-bind="v"
            v-model="form[v.name]"
            :disabled="disabled || v.readonly"
            :placeholder="v.placeholder || `请选择${v.title}${v.required ? '（必填）' : ''}`"
            :type="v.isText ? 'text' : ''"
            @change="res => v.callback && v.callback(res)"
          />
          <!-- 隐藏 -->
          <input v-else-if="v.type == 'hidden'" v-model="form[v.name]" type="hidden">
          <!-- 字典选项 -->
          <DictSelect
            v-else-if="v.type == 'dict'"
            v-bind="v"
            v-model="form[v.name]"
            :placeholder="v.placeholder || `请选择${v.title}${v.required ? '（必填）' : ''}`"
            :disabled="disabled || v.readonly"
          />
          <!-- 富文本 -->
          <Editor
            v-if="v.type == 'editor'"
            v-model="form[v.name]"
            v-bind="v"
            :disabled="disabled || v.readonly"
          />
          <!-- 滑块 -->
          <el-slider
            v-if="v.type == 'slider'"
            v-model="form[v.name]"
            v-bind="v"
            style="margin: 0 10px"
            :disabled="disabled || v.readonly"
            @change="res => v.callback && v.callback(res)"
          />
          <!-- 插槽 -->
          <slot v-else-if="v.type == 'slot'" :name="v.slotName" :form="form" />
          <Addr
            v-else-if="v.type == 'addr'"
            v-model="form[v.name]"
            style="width: 100%"
            v-bind="v"
            @change="res => changeAddr(res)"
          />
          <el-input
            v-else-if="v.type == 'textClick'"
            v-model="form[v.name]"
            :disabled="disabled || v.readonly"
            :maxlength="v.maxLen || 200"
            :clearable="!v.noClear"
            :placeholder="v.placeholder || `请输入${v.title || ''}${v.required ? '（必填）' : ''}`"
          >
            <template #append><el-button icon="Search" @click="v.click(form[v.name])" /></template>
          </el-input>
          <!-- 默认输入框 -->
          <el-input
            v-else-if="v.type == 'input' || !v.type"
            v-model="form[v.name]"
            :disabled="disabled || v.readonly"
            :maxlength="v.maxLen || 200"
            :clearable="!v.noClear"
            :placeholder="v.placeholder || `请输入${v.title}${v.required ? '（必填）' : ''}`"
          />
        </el-form-item>
      </el-col>

      <el-col
        v-if="!hideBtn && layout == 'inline' && formInfoTmp.length > 4"
        :span="24"
        class="morehr"
      />
      <el-col v-if="!hideBtn" :span="formInfoTmp.length < 4 ? 24 / splice : 24">
        <el-form-item label-width="0">
          <div
            :class="
              layout != 'inline' || hideMore || formInfoTmp.length > 3
                ? 'btn-wrap'
                : 'btn-sub' + ' ' + layout
            "
          >
            <slot name="formSlot" />
            <el-button
              v-if="layout == 'inline' && hideMore"
              :icon="!toggle ? 'ArrowDown' : 'ArrowUp'"
              @click="toggle = !toggle"
            >
              {{ toggle ? '收起' : '展开' }}
            </el-button>

            <el-button type="primary" :size="size" icon="search" @click="subForm()">
              搜索
            </el-button>
            <el-button :size="size" icon="Refresh" @click="reset()">重置</el-button>
          </div>
        </el-form-item>
      </el-col>
      <el-col :span="24">
        <slot />
      </el-col>
    </el-row>
  </el-form>
</template>
<script>
  import _ from 'lodash'
  export default {
    name: 'CommonForm',
    props: {
      splice: {
        type: [Number, String],
        default: 4
      },
      modelValue: {
        type: Object,
        default: () => {}
      },
      rules: {
        type: Object,
        default: () => {}
      },
      formInfo: {
        type: Array,
        default: () => []
      },
      formType: {
        type: String,
        default: 'formData'
      },
      size: {
        type: String,
        default: 'default'
      },
      layout: {
        type: String,
        default: 'inline'
      },
      autoEmit: {
        type: Boolean,
        default: true
      },
      hideBtn: {
        type: Boolean,
        default: false
      },
      labelWidth: {
        type: [String, Number],
        default: '120px'
      },
      disabled: {
        type: Boolean,
        default: false
      },
      type: {
        type: String,
        default: 'form'
      },
      beforReset: {
        type: Function,
        default: null
      }
    },
    emits: ['sub', 'cancel'],
    data() {
      return {
        toggle: false,
        form: _.cloneDeep(this.modelValue),
        tmpRangAttr: [],
        freshKey: null
      }
    },
    computed: {
      formInfoTmp() {
        return _.cloneDeep(this.formInfo).filter(v => v.type != 'hidden')
      },
      hideMore() {
        return (
          this.formInfo.filter(v => v.type != 'hidden').length > this.splice &&
          this.layout == 'inline'
        )
      },
      hastime() {
        return this.formInfo.filter(v => ['time', 'range', 'date'].includes(v.type)).length > 0
      }
    },
    mounted() {
      // this.parseForm()
      this.autoEmit &&
        this.$nextTick(() => {
          this.subForm()
        })
    },
    methods: {
      //下拉列表变更回调
      changeSelect(value, row) {
        let obj = null
        if (row.multi) {
          obj = row.child.filter(v => value.includes(v.value))
        } else {
          obj = row.child.find(v => v.value == value)
        }
        row.callback && row.callback({ value, obj })
      },
      parseForm(arr) {
        const Obj = {}
        arr = arr || this.formInfo
        arr.map(v => {
          if (
            ['range', 'daterange', 'rangNum', 'datetimerange'].includes(v.type) &&
            Array.isArray(v.value) &&
            v.value.length &&
            Array.isArray(v.childName)
          ) {
            Obj[v.childName[0]] = v.value[0]
            Obj[v.childName[1]] = v.value[1]
          }
          Obj[v.name] = v.value
        })
        this.form = Obj
      },
      changeAddr(res) {
        this.form = Object.assign({}, this.form, res)
      },
      setFormParams(params = {}) {
        this.form = Object.assign({}, this.form, params)
      },
      setFormItem(params = {}) {
        let item = null
        let index = -1
        this.formInfo.map((v, i) => {
          if (v.name == params.name) {
            item.v
            index = i
          }
        })
        item = Object.assign({}, item, params.data)
      },
      reset() {
        // this.parseForm()
        this.$refs.ruleForm.resetFields()
        this.freshKey = Date.now()
        this.beforReset && this.beforReset()
        this.$emit('cancel', this.getForm())
      },
      getForm() {
        const res = _.cloneDeep(this.form)
        this.formInfo.map(v => {
          //区间类型 数组结果转成2个字段
          if (
            ['range', 'daterange', 'datetimerange', 'monthrange'].includes(v.type) &&
            Array.isArray(res[v.name])
          ) {
            if (v.childName) {
              res[v.childName[0]] = res[v.name][0]
              res[v.childName[1]] = res[v.name][1]
              delete res[v.name]
            } else {
              //不是区间的数组转成字符串
              res[v.name] = res[v.name] ? res[v.name].join() : res[v.name]
            }
          }
          // noAttr 删除对应form属性，只用于展示内容
          if (v.noAttr) {
            delete res[v.name]
          }
          if (
            (v.type == 'cuselect' || v.type == 'select' || v.type == 'dict') &&
            !v.noArr &&
            v.multi &&
            this.formType == 'formData'
          ) {
            // res[v.name] = res[v.name] ? res[v.name].join(',') : res[v.name]
          }
        })
        return res
      },
      subForm(cb = null) {
        return new Promise((resolve, reject) => {
          this.$refs.ruleForm.validate((valid, error) => {
            if (valid) {
              try {
                const form = this.getForm()
                this.$emit('sub', form)
                cb && cb(form)
                resolve(form)
              } catch (err) {
                console.log('表单取值失败', err)
              }
            } else {
              let err = ''
              for (const i in error) {
                err = error[i][0].message
                break
              }
              console.log('表单校验失败，错误字段：', err)
              this.$message.error(err)
              reject(new Error(err))
            }
          })
        })
      }
    }
  }
</script>
<style lang="scss">
  .hide-item {
    display: none !important;
  }
  .common-form {
    .el-calendar-picker,
    .el-select,
    .el-input-number,
    .info-value,
    .el-date-editor,
    .el-row,
    .common-form-item,
    .el-input-affix-wrapper {
      width: 100%;
      vertical-align: middle;
    }
    .el-form-item-control {
      min-width: 100%;
    }
    .inline-style-full {
      .el-input-affix-wrapper,
      .el-form-item-control,
      .file-upload {
        width: 100%;
      }
    }
  }
  .blocktime {
    .el-calendar-picker {
      width: 100% !important;
    }
  }
  .btn-wrap {
    text-align: right;
    width: 100%;
  }
  .btn-sub {
    padding-left: 1em;
  }
  .common-form {
    .el-form-explain {
      display: none !important;
    }
    .el-form-item-control-wrapper {
      flex: 1;
    }
    .el-form-item-label {
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
    }
    .morehr {
      flex: 0 0 100%;
      margin: 0 0 1rem;
      border-bottom: 1px solid var(--el-border-color);
    }
  }
  .el-form--small .modehr {
    margin-bottom: 12px !important;
  }
  .fixtimew {
    .el-input-affix-wrapper,
    .el-input,
    .el-select,
    .el-calendar-picker {
      width: 100%;
    }
  }

  .rotate {
    transform: rotate(180deg);
  }
</style>
